<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>vue双向数据绑定实现</title>
</head>
<body>
	<div id="app">
		<input type="text" id="a" v-model="text">
		{{ text }}
	</div>

	<script>

		function Watcher(vm, node, name, nodeType) {
			Dep.target = this;
			this.name = name;
			this.node = node;
			this.vm = vm;
			this.nodeType = nodeType;
			this.update();
			Dep.target = null;
		}

		Watcher.prototype = {
			update: function () {
				this.get();
				// console.info(this.nodeType);
				if (this.nodeType == 'text') {
					this.node.nodeValue = this.value;
				}
				if (this.nodeType == 'input') {
					this.node.value = this.value;
				}
			},
			get: function () {
				this.value = this.vm[this.name];
			}
		}

		function Dep() {
			this.subs = [];
		}

		Dep.prototype = {
			addSub: function (sub) {
				this.subs.push(sub);
			},

			notify: function () {
				this.subs.forEach(function (sub) {
					sub.update();
				})
			}
		}

		let vm = new Vue({
			el:'app',
			data:{
				text:'hello world',
			}
		})

		function Vue(options) {
			this.data = options.data;
			let data = this.data;
			observe(data, this);

			let id = options.el;
			let dom = nodeToFragment(document.getElementById(id), this);
			// console.info(dom);
			document.getElementById(id).appendChild(dom);
		}

		function defineReactive(obj, key, val) {
			let dep = new Dep();
			Object.defineProperty(obj, key, {
				get: function () {
					if (Dep.target) {
						dep.addSub(Dep.target);
					}
					return val;
				},
				set:function (newVal) {
					if (newVal === val) {return}
					val = newVal;
					console.info(val);
					dep.notify();
				}
			});
		}

		function observe(obj, vm) {
			Object.keys(obj).forEach(function (key){
				defineReactive(vm, key, obj[key]);
			});
		}

		function nodeToFragment(node, vm) {
			let flag = document.createDocumentFragment();
			let child;

		 	while(child = node.firstChild){
		 		compile(child, vm);
		 		flag.append(child);
		 	}
		 	return flag;
		}


		function compile(node, vm) {
			let reg = /\{\{(.*)\}\}/;
			// 元素节点
			if (node.nodeType === 1) {
				let attr = node.attributes;
				let name = '';

				for(let i = 0; i < attr.length; i++){
					if (attr[i].nodeName == 'v-model') {
						name = attr[i].nodeValue;

						node.addEventListener('input', function (e) {
							vm[name] = e.target.value;
						})
						// node.value = vm[name];
						node.removeAttribute('v-model');
					}
				}
				new Watcher(vm, node, name, 'input');
			}
			// text节点
			if (node.nodeType === 3) {
				if (reg.test(node.nodeValue)) {
					let name = RegExp.$1;
					name = name.trim();
					// node.nodeValue = vm[name];
					
					new Watcher(vm, node, name, 'text');
				}
			}
		}
	</script>
</body>
</html>